home *** CD-ROM | disk | FTP | other *** search
Text File | 1996-12-18 | 13.1 KB | 347 lines | [TEXT/3PRM] |
- module FractalDemo
-
- /*
- An interactive fractal drawing program.
-
- This program uses the 0.8 I/O library.
-
- This program requires a system with at least 256 colors.
- To really create beautiful fractals in a reasonable time
- you need a system with mathematical co-processor.
-
- Run the program using the "No Console" option (Application options).
- */
-
- import StdInt, StdMisc, StdString, StdBool, StdReal, StdArray, StdTuple
- import Mandelbrot, deltaDialog, deltaControls
-
- :: ZoomFunction :== ZoomState -> Area -> Area
-
- Colour1 :== (0,99,4,99,2,60)
- Colour2 :== (4,99,0,99,2,75)
- Colour3 :== (4,99,2,70,0,99)
- Colour4 :== (0,80,1,80,3,60)
- Colour5 :== (2,99,0,99,1,99)
-
- Start :: *World -> *World
- Start world
- # (events,world)
- = OpenEvents world
- (_,events) = StartIO [window, menu, timer] InitState [] events
- world = CloseEvents events world
- = world
- where
- window = WindowSystem
- [ FixedWindow MyWindow MyPos "Fractal Demo"
- ((0,0),(ScreenWidth, ScreenHeight))
- FractalUpdate
- [ GoAway Quit
- , Mouse Unable (Track ZoomInArea)
- ]
- ]
- menu = MenuSystem [file, options, commands]
- file = PullDownMenu FileID "File" Able
- [ MenuItem QuitID "Quit" (Key 'Q') Able Quit
- ]
- options = PullDownMenu OptionsID "Options" Able
- [ SubMenuItem FixedDepthsID "Fixed depths" Able
- [ MenuRadioItems Depth128ID
- [ MenuRadioItem Depth32ID "32" NoKey Able (DefDepth 32)
- , MenuRadioItem Depth64ID "64" NoKey Able (DefDepth 64)
- , MenuRadioItem Depth128ID "128" NoKey Able (DefDepth 128)
- , MenuRadioItem Depth256ID "256" NoKey Able (DefDepth 256)
- , MenuRadioItem Depth512ID "512" NoKey Able (DefDepth 512)
- , MenuRadioItem Depth1024ID "1024" NoKey Able (DefDepth 1024)
- ]
- ]
- , MenuSeparator
- , SubMenuItem AreasID "Predefined Areas" Able
- [ CheckMenuItem Area1ID "normal mandelbrot"
- NoKey Able Mark (DefArea Area1ID {center=(0.75,0.0),width=3.0,height=2.0})
- , CheckMenuItem Area2ID "head"
- NoKey Able NoMark (DefArea Area2ID {center=(1.26,0.0),width=1.0,height=0.7})
- , CheckMenuItem Area3ID "spike"
- NoKey Able NoMark (DefArea Area3ID {center=(1.54,0.0),width=0.20,height=0.14})
- , CheckMenuItem Area4ID "spike detail"
- NoKey Able NoMark (DefArea Area4ID {center=(1.4814,-0.0013),width=0.0366,height=0.0278})
- , CheckMenuItem Area5ID "back valley"
- NoKey Able NoMark (DefArea Area5ID {center=(-0.2963,-0.0152),width=0.1057,height=0.0926})
- , CheckMenuItem Area6ID "head valley"
- NoKey Able NoMark (DefArea Area6ID {center=(0.8,-0.2),width=0.37,height=0.29})
- , CheckMenuItem Area7ID "antenna"
- NoKey Able NoMark (DefArea Area7ID {center=(0.9203,-0.2889),width=0.0597,height=0.0606})
- ]
- , MenuSeparator
- , SubMenuItem FunctionsID "Mandelbrot Functions" Able
- [ MenuRadioItems Function1ID
- [ MenuRadioItem Function1ID "z = z*z + c" NoKey Able (DefaultFunction MSquare)
- , MenuRadioItem Function2ID "z = z*z*z + c" NoKey Able (DefFunction MCube)
- , MenuRadioItem Function3ID "z = sin z + c" NoKey Able (DefFunction MSin)
- , MenuRadioItem Function4ID "z = cos z + c" NoKey Able (DefFunction MCos)
- , MenuRadioItem Function5ID "z = exp z + c" NoKey Able (DefFunction MExp)
- ]
- ]
- , MenuSeparator
- , SubMenuItem ColoursID "Predefined Palettes" Able
- [ MenuRadioItems Colour1ID
- [ MenuRadioItem Colour1ID "Red" NoKey Able (SetColour Colour1)
- , MenuRadioItem Colour2ID "Green" NoKey Able (SetColour Colour2)
- , MenuRadioItem Colour3ID "Blue" NoKey Able (SetColour Colour3)
- , MenuRadioItem Colour4ID "Camouflage" NoKey Able (SetColour Colour4)
- , MenuRadioItem Colour5ID "Pastel" NoKey Able (SetColour Colour5)
- ]
- ]
- , MenuItem 1000 "Set Palette..." (Key 'P') Able SetPalette
- ]
- commands = PullDownMenu CommandsID "Commands" Able
- [ MenuItem DrawID "Draw Mandelbrot" (Key 'M') Able DoMandelDraw
- , MenuSeparator
- , MenuItem ZoomInID "Zoom in" (Key 'Z') Unable (DoZoomFractal ZoomInArea)
- , MenuItem ZoomOutID "Zoom out" (Key 'O') Unable (DoZoomFractal ZoomOutArea)
- , MenuSeparator
- , MenuItem StopDrawID "Halt Drawing" (Key 'S') Unable DoHaltDrawing
- , MenuItem ContinueID "Continue Drawing" NoKey Unable DoContinueDrawing
- ]
- timer = TimerSystem [Timer TimerID Unable 0 DrawFractal]
-
- InitState :: *FractalState
- InitState
- = { funstate = { area = {center=(0.75,0.0),width=3.0,height=2.0}
- , colours = Colour1
- , depth = 128
- , fun = MSquare
- }
- , drawstate = { layer = 0
- , grain = 0
- , line = 0
- }
- , zoomstate = ((0,0),(0,0))
- }
-
- /* Real update:
- */
-
- FractalUpdate :: UpdateArea *FractalState -> (*FractalState, [DrawFunction])
- FractalUpdate [] state
- = (state,[])
- FractalUpdate _ state=:{drawstate={layer=0,grain=0,line=0}}
- = (state,[])
- FractalUpdate upd_area state
- = FractalUpdate` upd_area state
- where
- FractalUpdate` :: UpdateArea *FractalState -> (*FractalState, [DrawFunction])
- FractalUpdate` [first:rest] state
- # (state, update_area) = UpdateFractalArea first state
- (state, update_rest) = FractalUpdate` rest state
- = (state, [update_area:update_rest])
- FractalUpdate` _ state
- = (state,[])
-
-
- /* File menu function:
- */
-
- Quit :: *FractalState IO -> (*FractalState, IO)
- Quit state io = (state, QuitIO io)
-
-
- /* Options menu functions:
- */
-
- DefDepth :: CalcDepth *FractalState IO -> (*FractalState, IO)
- DefDepth depth state io
- = (SetCalcDepth depth state,io)
-
- DefArea :: MenuItemId Area *FractalState IO -> (*FractalState, IO)
- DefArea id area state io
- = (SetArea area state,MarkMenuItems [id] (UnmarkAreas io))
-
- DefFunction :: FractalFunction *FractalState IO -> (*FractalState, IO)
- DefFunction func state io
- = (SetFFunction func state,DisableMenuItems [Area1ID,Area2ID,Area3ID,Area4ID,Area5ID,Area6ID,Area7ID] io)
-
- DefaultFunction :: FractalFunction *FractalState IO -> (*FractalState, IO)
- DefaultFunction func state io
- = (SetFFunction func state,EnableMenuItems [Area1ID,Area2ID,Area3ID,Area4ID,Area5ID,Area6ID,Area7ID] io)
-
- SetColour :: Colours *FractalState IO -> (*FractalState, IO)
- SetColour colour=:(rd,ri,gd,gi,bd,bi) state io
- = ( SetNrOfColours colour state
- , ChangeDialog 1
- [ ChangeSliderBar 12 (rd*10+5), ChangeDynamicText 13 (toString rd)
- , ChangeSliderBar 22 ri , ChangeDynamicText 23 (toString ri)
- , ChangeSliderBar 32 (gd*10+5), ChangeDynamicText 33 (toString gd)
- , ChangeSliderBar 42 gi , ChangeDynamicText 43 (toString gi)
- , ChangeSliderBar 52 (bd*10+5), ChangeDynamicText 53 (toString bd)
- , ChangeSliderBar 62 bi , ChangeDynamicText 63 (toString bi)
- ] io
- )
-
- SetPalette :: *FractalState IO -> (*FractalState, IO)
- SetPalette state=:{funstate={colours=(rd,ri,gd,gi,bd,bi)}} io
- = (state,OpenDialog dialog io)
- where
- dialog = CommandDialog 1 "Palette" [ItemSpace (Pixel 6) (Pixel 12)] 1
- [ ColourText 11 Left RedColour "Depth:"
- , PaletteSlider 12 (RightTo 11) (rd*10+5) 10
- , DynamicText 13 (RightTo 12) (Pixel 30) (toString rd)
- , ColourText 21 (YOffset 11 (Pixel 6)) RedColour "Brightness:"
- , PaletteSlider 22 (RightTo 21) ri 1
- , DynamicText 23 (RightTo 22) (Pixel 30) (toString ri)
- , ColourText 31 Left GreenColour "Depth:"
- , PaletteSlider 32 (RightTo 31) (gd*10+5) 10
- , DynamicText 33 (RightTo 32) (Pixel 30) (toString gd)
- , ColourText 41 (YOffset 31 (Pixel 6)) GreenColour "Brightness:"
- , PaletteSlider 42 (RightTo 41) gi 1
- , DynamicText 43 (RightTo 42) (Pixel 30) (toString gi)
- , ColourText 51 Left BlueColour "Depth:"
- , PaletteSlider 52 (RightTo 51) (bd*10+5) 10
- , DynamicText 53 (RightTo 52) (Pixel 30) (toString bd)
- , ColourText 61 (YOffset 51 (Pixel 6)) BlueColour "Brightness:"
- , PaletteSlider 62 (RightTo 61) bi 1
- , DynamicText 63 (RightTo 62) (Pixel 30) (toString bi)
- , DialogButton 1 Center "OK" Able PaletteOK
- ]
-
- ColourText :: DialogItemId ItemPos Colour String -> DialogItem *FractalState IO
- ColourText id pos col text
- = DialogIconButton id pos domain (DrawText ascent col text) Unable (\_ state io -> (state,io))
- where
- domain = ((0,0),(wid,ascent+descent+leading))
- wid = FontStringWidth "Brightness:" dfont
- (ascent,descent,_,leading) = FontMetrics dfont
- (_,dfont) = SelectFont font style size
- (font,style,size) = DefaultFont
-
- DrawText :: Int Colour String SelectState -> [DrawFunction]
- DrawText y col text a = [SetPenColour col, MovePenTo (0,y), DrawString text]
-
- PaletteSlider :: DialogItemId ItemPos SliderPos Int -> DialogItem *FractalState IO
- PaletteSlider id pos slider val
- = SliderBar id pos Able Horizontal slider 99 (ChangeValue id val)
- where
- ChangeValue :: DialogItemId Int DialogInfo (DialogState *FractalState IO) -> DialogState *FractalState IO
- ChangeValue id val dinfo dstate
- = ChangeDynamicText (id+1) (toString pos) dstate
- where
- pos = GetSliderPosition id dinfo / val
-
- PaletteOK :: DialogInfo *FractalState IO -> (*FractalState, IO)
- PaletteOK dialog state io
- = (SetNrOfColours (rd,ri,gd,gi,bd,bi) state,ActivateWindow MyWindow io)
- where
- rd = GetSliderPosition 12 dialog / 10
- ri = GetSliderPosition 22 dialog
- gd = GetSliderPosition 32 dialog / 10
- gi = GetSliderPosition 42 dialog
- bd = GetSliderPosition 52 dialog / 10
- bi = GetSliderPosition 62 dialog
-
- /* Commands Menu functions:
- */
-
- DoZoomFractal :: ZoomFunction *FractalState IO -> (*FractalState,IO)
- DoZoomFractal zoomfunc state io
- # io = EnableMouse MyWindow io
- io = DisableTimer TimerID io
- io = DisableMenus [OptionsID,CommandsID] io
- io = ChangeMouseFunction MyWindow (Track zoomfunc) io
- = (state,io)
-
- DoMandelDraw :: *FractalState IO -> (*FractalState,IO)
- DoMandelDraw state io
- # io = EnableTimer TimerID io
- io = DisableMenus [OptionsID] io
- io = EnableMenuItems [StopDrawID,ZoomInID,ZoomOutID] io
- io = DisableMenuItems [DrawID,ContinueID] io
- = (InitDrawState state,io)
-
- DoHaltDrawing :: *FractalState IO -> (*FractalState,IO)
- DoHaltDrawing state io
- # (state,io) = DoStopDrawing state io
- io = EnableMenuItems [ContinueID] io
- = (state,io)
-
- DoContinueDrawing :: *FractalState IO -> (*FractalState,IO)
- DoContinueDrawing state io
- # io = EnableTimer TimerID io
- io = DisableMenus [OptionsID] io
- io = EnableMenuItems [StopDrawID,ZoomInID,ZoomOutID] io
- io = DisableMenuItems [DrawID,ContinueID] io
- = (state,io)
-
- // Zooming
- Track :: ZoomFunction MouseState *FractalState IO -> (*FractalState,IO)
- Track zoomfun (_,ButtonUp,_) state=:{funstate={area},zoomstate} io
- | TooSmall zoom` = ( state
- , ChangeIOState
- [ EnableMenus [OptionsID,CommandsID]
- , EnableMenuItems [DrawID]
- , DisableMenuItems [StopDrawID]
- , DrawInWindow MyWindow [ReadyZoom zoomstate]
- ] io
- )
- | otherwise = ( InitDrawState (SetArea (zoomfun zoom` area) state)
- , ChangeIOState
- [ UnmarkAreas
- , EnableMenus [CommandsID]
- , DisableMenuItems [DrawID,ContinueID]
- , EnableMenuItems [ZoomInID,ZoomOutID,StopDrawID]
- , DisableMouse MyWindow
- , EnableTimer TimerID
- , DrawInWindow MyWindow [ReadyZoom zoomstate]
- ] io
- )
- where
- zoom` = CorrectRect zoomstate
-
- CorrectRect :: Rectangle -> Rectangle
- CorrectRect ((x1,y1),(x2,y2)) = ((min x1 x2,min y1 y2),(max x1 x2,max y1 y2))
-
- TooSmall :: Rectangle -> Bool
- TooSmall ((x1,y1),(x2,y2)) = x2-x1<8 || y2-y1<8
-
- ReadyZoom :: Rectangle Picture -> Picture
- ReadyZoom rect p = SetPenNormal (DrawRectangle rect p)
- Track _ (point,ButtonStillDown,_) state=:{zoomstate} io
- | last==point = ( state,io)
- | otherwise = ( SetZoomState rect` state
- , DrawInWindow MyWindow [DrawFrame zoomstate rect`] io
- )
- with
- rect` = (base,point)
- where
- (base,last) = zoomstate
-
- DrawFrame :: Rectangle Rectangle Picture -> Picture
- DrawFrame oldrect rect p = DrawRectangle rect (DrawRectangle oldrect p)
- Track _ (point,ButtonDown,_) state io
- = (SetZoomState rect` state,DrawInWindow MyWindow [ZoomFrame rect`] io)
- where
- rect` = (point,point)
-
- ZoomFrame :: Rectangle Picture -> Picture
- ZoomFrame rect p = DrawRectangle rect (SetPenMode XorMode (SetPenColour BlackColour p))
- Track _ _ state io = (state,io)
-
- ZoomInArea :: ZoomState Area -> Area
- ZoomInArea ((x1,y1),(x2,y2)) {center=(xc,yc),width,height}
- = {center=(centerx,centery),width=newwidth,height=newheight}
- where
- centerx = xc + width /toReal ScreenWidth * (toReal (x1+x2-ScreenWidth) / 2.0)
- centery = yc + height/toReal ScreenHeight* (toReal (y1+y2-ScreenHeight)/ 2.0)
- newwidth = width *(toReal (x2-x1) / toReal ScreenWidth )
- newheight = height*(toReal (y2-y1) / toReal ScreenHeight)
-
- ZoomOutArea :: ZoomState Area -> Area
- ZoomOutArea ((x1,y1),(x2,y2)) {center=(xc,yc),width,height}
- = {center=(centerx,centery),width=newwidth,height=newheight}
- where
- centerx = xc - newwidth / toReal ScreenWidth * (toReal (x1+x2-ScreenWidth) / 2.0)
- centery = yc - newheight/ toReal ScreenHeight * (toReal (y1+y2-ScreenHeight)/ 2.0)
- newwidth = toReal ScreenWidth /toReal (x2-x1)*width
- newheight = toReal ScreenHeight/toReal (y2-y1)*height
-
- UnmarkAreas :: (IOState s) -> IOState s
- UnmarkAreas io = UnmarkMenuItems AreaIds io
-